Javiera Alegría, Adriana Concha, Erick Perez, Alonso Uribe
En el presente proyecto se busca poner en práctica los conocimientos adquiridos a lo largo del curso Introducción a la Minería de Datos, para ello se realizará un análisis de datos recogidos sobre Matrículas de Educación Superior entre los años 2010 y 2019. La fuente del set de datos corresponde al Servicio de Información de Educación Superior (SIES) y presenta un registro de 1.2 millones de matrículas aproximadamente por año, con información relacionada a nombre de la sede, región de la sede, rango de edad del matriculado, entre otros que se detallan más adelante.
La relevancia de estos datos radica en que, al realizar un análisis sobre ellos, podríamos obtener información que ayude a mejorar el acceso a la educación superior. Lo anterior, a través de información respecto a la demanda de educación y el cómo ésta se distribuye en la sociedad, lo que permitiría atacar de forma eficiente sesgos o problemáticas sociales inherentes a este proceso. También nos permite observar rasgos característicos que llevan a la deserción en la educación superior y, por ende, facilitar la búsqueda de soluciones a estos problemas.
En esta sección se describe el proceso realizado para adaptar el conjunto de datos, con el fin de poder trabajar con ellos, y, además, el proceso a través del cual se logró entender los datos y así plantearse preguntas acorde.
Esta información se obtuvo del documento disponible en la página de descarga de los datos, en él se describe
cada columna y, en algunos casos, se indican los valores posibles. Además, para observar en detalle las columnas
se utilizaron las siguientes funciones de la librería Pandas, el output se adjunta en la sección
Anexos, DataSet;
import pandas as pd
# df5 corresponde al DataFrame de Pandas en donde se cargaron los datos del año 2015
df5.info()
df5.describe()
df5.head(n=20)
for col in list(df5):
df5[[col]].drop_duplicates()
Para comprender mejor el dataset, se graficó la cantidad de datos anuales y el porcentaje de datos nulos en cada año, ambos gráficos se muestran a continuación y sus códigos respectivos se muestran en la sección Anexos, DataSet.
En este ámbito se busca homogeneizar el tipo de dato para cada columna y la forma en que se representa un valor
nulo a lo largo de todos los datos. De esta manera, se reemplazan las distintas formas de un dato nulo a el
valor Nan de la librería numpy y se transforman los tipos de datos de las columnas a
un solo tipo para cada una. El código principal se muestra en Anexos, Limpieza de datos.
Desechamos ciertas columnas redundantes o con alta correlación, que a simple vista describen el mismo fenómeno con distintos niveles de detalle. Aún así, nos reservamos la posibilidad de utilizar cualquier columna que consideremos necesaria para futuros análisis. Este procedimiento, más que nada, es para hacernos una “vista panorámica” de la naturaleza de los datos, y con esto poder hacer preguntas más concretas.
Como en el dataset tenemos en su mayoría atributos nominales, con el propósito de observar alguna correlación entre ellos, los desplegamos mediante la vectorización “One Hot Encoding”, ésta consiste en representar el atributo como un vector de dimensión igual a la cantidad de valores distintos en dicho atributo, y asignar para cada valor un vector ortonormal a todos los demás. Luego de esto, fue posible generar una matriz de correlación con los valores desplegados de los siguientes atributos;
nivel_carrera_2: Tipo de grado académico entregado por la carrera.region_sede: Región de la sede.area_conocimientotipo_inst_2: Clasificación del tipo de instituciónacreditada_carr: Situación de acreditación de la carrera o programa informada por la
institución al 30 de abril del año del proceso. acreditada_inst: Situación acreditación de institución al 30 de abril del año en proceso.jornadarango_edad requisito_ingresotipo_plan_carr: Distinción dada por el tipo plan que posee la carrera o programa.vigencia_carrera: Tipo de vigencia.El código a continuación permite obtener un heatmap de la correlación entre todos los años.
import seaborn
df_all = pd.concat([df0, df1, df2, df3, df4, df5, df6, df7, df8, df9])
correlation = df_all.corr()
seaborn.heatmap(correlation)
<AxesSubplot:>
Por otro lado, para aplicar One Hot a las columnas del año 2011, 2015 y 2019, primero se obtienen los
tipos de cada columa en un dataframe, luego, para cada columna, se verfica si su tipo es object y
si no corresponde a columnas con datos nominales arbitrarios o presentes en un solo año. Así, a las columnas que
pasan el filtro se les aplica One Hot y se guarda su resultado en un archivo .csv. El
código especifico se muestra en Anexos, OneHot.
En el bloque a continuación se seleccionan las columnas a utilizar del dataframe que no requieren ser transformadas, luego, se seleccionan las columnas que si requieren transformación y se quieren utilizar en la correlación. Entre ambos conjuntos se hace merge para obtener un solo DataFrame con toda la información.
cols_to_drop = ["costo_obtencion_titulo_diploma", "costo_tit_explicacion_observacion", "costo_proceso_titulacion", "forma_ingreso", "nivel_global", "nivel_carrera_1", "comuna_sede", "provincia_sede", "area_carrera_generica", "oecd_area", "oecd_subarea", "tipo_inst_1", "tipo_inst_3", "modalidad"]
df_sub_one_hot = df_sub.drop(columns=cols_to_drop)
one_hot_cols = ["nivel_carrera_2", "region_sede", "area_conocimiento", "tipo_inst_2", "acreditada_carr", "acreditada_inst", "jornada", "rango_edad", "requisito_ingreso", "tipo_plan_carr", "vigencia_carrera"]
for col in one_hot_cols:
df_aux = pd.read_csv("one_hot/one_hot_" + col + ".csv")
df_sub_one_hot = pd.merge(df_sub_one_hot, df_aux, left_index=True, right_index=True)
Sobre el DataFrame obtenido se busca la correlación y el resultado se muestra en un HeatMap adjuntado en Anexos, HeatMap de los datos. Para una mejor comprensión del resultado a continuación se muestra la versión interactiva del HeatMap obtenido.
Como primera visualización es interesante analizar la distribución del costo de los aranceles entre las distintas regiones del país, como también el incremento de estos a lo largo de los años; para lo anterior se transforman los datos agrupando por rango de edad, genero y área de conocimiento, luego se cuenta la cantidad de aparaciones de cada triplete por año, por último se promedian los valores encontrados por año. El código para obtener los datos a graficar se adjunta en la sección Anexos, Comportamiento de los datos.
Así se obtiene la siguiente figura utilizando D3.js. Esta responde, finalmente, a la pregunta ¿Cómo se relaciona el área de conocimiento de la carrera con la edad y género de la persona que se matricula?. En ella podemos ver una tendencia marcada que se condice con los roles de género establecidos socialmente.
Relación entre Área de conocimiento, edad y género
Para continuar comprendiendo los datos, nos planteamos la pregunta ¿Existe una correlación entre el costo de las carreras y su ubicación geográfica? ¿Varía esto a través de los años?, para ello se selecciona el código de la carrera, el valor del arancel y la región de la sede, se eliminan los duplicados y se agrupan por región para obtener el promedio de los valores de arancel de las diferentes carreras. Lo anterior se hace para los años 2011, 2013, 2015, 2017 y 2019. Por último, se normaliza según la UF de cada año comprendiendo que los datos originales están en pesos chilenos y esta moneda se ve afectada por la inflación anualmente.
El código específico se muestra en la sección Anexos, Comportamiento de los datos. Con el fin de comprender mejor los datos finales, estos se expotaron al software Tableu para graficar.
Se extrae de la imagen que el valor (promedio) de los aranceles varían por región, siendo el valor más alto en la Región Metropolitana. También al analizar por año, se ve un incremento en Unidades de Fomento (UFs) del valor de los aranceles.
En esta sección se detallan la metodología planteada en el hito 2, la implementación de cada pregunta y los resultados obtenidos.
Esta pregunta está mayormente respondida y diseñada por Alonso Uribe
Antes de esto hay que replantearse la pregunta, y para esto se debe definir concretamente cuáles son las características de las matrículas. En el caso de que fueran instancias, es decir, cada matrícula ingresada, entonces esta pregunta sería equivalente a la pregunta dos: debemos predecir características en personas, aunque en este caso no nos estaríamos centrando en personas que se cambian de carrera. En el caso de que fueran características macroscópicas, se deben evitar preguntas triviales, que involucren directamente indicadores como promedios, varianzas, número de sucesos, etc., que debieron ser estudiadas en el hito anterior. Una alternativa interesante podría ser generar clusters con los vectores totales (luego aplicar one hot) de cada instancia. y ver su evolución temporal: ¿dónde está el centro de cada uno, por año?, ¿cómo van cambiando ciertos indicadores de validación: Inercia, Separación, Cohesión,?, ¿cómo va cambiando la densidad de clusters?. Junto a esto podemos ir comparando con valores más tangibles como promedios, varianzas, etc. (ej: varianza regional del valor de arancel).
Para responder esta pregunta, se deben completar tres pasos previos:
Utilizar nuevamente como vectorización preliminar one hot encoding para ingresar las instancias como vectores de dimensión igual al número de columnas. Habrá que tener cuidado interpretando los clusters y el espacio vectorial en el que residen. En este vector, por ejemplo, la columna de rango de edad (ej: 18 y 20 años) tendría igual peso que la del tipo de estudio superior (ej: Doctorado); los dos marcarían un 1 en su dimensión correspondiente, y en las demás, de su misma naturaleza, un 0.
Generar Clustering con ciertos atributos seleccionados gracias a la exploración realizada en el hito 1. Con esto, y la correspondiente validación del clustering, podremos cuantificar potenciales patrones de agrupación.
2.1 Primeramente se utilizará el Coeficiente de Silhouette para verificar la viabilidad del cluster, si fuese negativo, se trataría de generar un vector (por instancia) preliminar compuesto de otra manera, o también podría ser interesante crear para cada columna un vector y comprobar si podemos, mediante algún tipo de operación, unificarlos todos, de forma que el clustering de cuenta de estructuras particulares.
2.2 Se hará uso de la métrica Cohesión, Separación e Inercia, junto a la visualización de su Matriz de proximidad, una vez encontrado un coeficiente de Silhouette positivo, con el propósito de seguir evaluando las estructuras subyacentes en los datos.
2.3 Podemos tomar este proceso como una forma sistemática de vectorizar instancias, de modo que luego quedar satisfechos (o de plano probar con varias) con un encoding podremos proseguir al paso 3.
Luego de tener un vector para cada instancia, podemos reducir su dimensionalidad y visualizar los clusters, como primera opción mediante PCA, pero existen varias por explorar. Luego de esto tendremos instancias medianamente interpretables, y que facilitarán su manejo en algoritmos de Regresión. Como ya se dijo en un inicio, otro posible estudio es el de la dinámica de los cluster, sus propiedades (ej: su densidad), y la correlación que estas variables guardan con indicadores macroscópicos en las matrículas(ej: valor arancel medio, arancel medio por región, etc.).
El grueso del código quedará en anexo. Enseguida, se describe a grandes rasgos la implementación.
Se selecciona nuevamente una colección de columnas relevantes para nuestra pregunta, como criterio de selección se consideran las que se puedan relacionar menos con instancias particulares y más con características macroscópicas en el año de matrículas.
Se genera un enconding para cada una de las columnas categóricas, dando valores ordinales a las columnas, para luego facilitar la conversión a one-hot enconding. Este one-hot consiste en un solo vector de ceros y unos, el que recopila todas las columnas.
Teniendo estos vectores, se explora diferentes métodos de clusterings, se selecciona K-Means, al dar los mejores resultados (aún asi deficientes) en Coef. de Silhouette, se encontró el número óptimo de clusters mediante el método del "codo". El clustering es exclusivamente realizado en espacio One-hot, no se ahonda en el movimiento realizado en otros espacios.
Método del "codo" entrega cualitativamente 20 clusters.
Coef. de Sillhouete de Clustering Jerarquico(ward): en espacio PCA; en espacio One-hot.
Coef. de Sillhouete de KMeans: en espacio PCA; en espacio One-hot.
Coef. de Sillhouete de DBSCAN: en espacio PCA; en espacio One-hot.
El seguimiento de los clusters a través de los años corresponde al desafio más importante de nuestro experimento. Para esto, los cluster se etiquetaron al seleccionar una columna relevante (arbitraria), y a cada cluster se le asigna el lugar n-ésimo en un contador de apariciones de un valor (nuevamente arbitrario) de la columna. De esta forma tenemos algún criterio para hacer un seguimiento a través de los años. Este criterio puede ser mayormente teorizado para mejorar la interpletabilidad del movimiento y su correlación con variables macroscópicas.
Enseguida se generó otro enconding mediante PCA (no se profundizo en la busqueda de métodos más avanzados de enconding). Como el proceso de PCA desde un enconding One-hot es costoso, se trabaja con una porción aleatoria de instancias de cada año. El año tiene alrededor de de instancias, se saco una muestra de instancias.
Luego, para cada año se grafica un scatterplot de los clusters etiquetados en estacio One-hot, genera una Matriz de Proximidad y, a su vez, se hace un seguimiento de cada cluster por separado, estos dos en espacio PCA.



Esta pregunta está mayormente respondida y diseñada por Javiera Alegria
Para responder la pregunta 2 primero es importante notar que es posible determinar quienes se han cambiado de carrera con los datos actuales, por lo tanto, se utilizará clasificación para buscar perfiles de personas que podrían cambiarse de carrera en el futuro. Así, las clases posibles son “se cambió de carrera” y “no se cambió de carrera”, y nuestra clase positiva corresponde a quienes sí se han cambiado de carrera, pues es lo que queremos evitar.
Entonces lo primero es disminuir la dimensionalidad de los datos, para esto se agregará una nueva columna que
describe el tiempo que lleva la persona cursando su carrera actual, así esta resume la información de las
columnas cat_periodo y ANIO_ING_CARR_ACT, su creación sería a través de la resta de
los años de ANIO_ING_CARR_ACT y cat_periodo. Por otro lado, se requiere una columna
que indique la clase de la fila, la que resumiría la información de las columnas ANIO_ING_CARR_ORI
y ANIO_ING_CARR_ACT; para obtenerla haremos una restricción con la siguiente query:
row.cat_periodo != row.anio_ing_carr_ori and row.cat_periodo == row.anio_ing_carr_act. De igual
manera, se utiliza la información de NIVEL_GLOBAL para limitar los datos a las matriculas de
pregrado, pues solo aquí tiene sentido el análisis.
Adicionalmente se mantendremos las siguientes columnas; GEN_ALU, RANGO_EDAD,
TIPO_INST_3, JORNADA, TIPO_PLAN_CARR, DUR_ESTUDIO_CARR,
NIVEL_CARRERA_1, VALOR_MATRICULA, VALOR_ARANCEL, OECD_AREA,
ACREDITADA_CARR, ACREDITADA_INST. Donde se incluye una sola columna relacionada a la
duración de la carrera pues se observa una estrecha relación entre DUR_ESTUDIO_CARR y DUR_TOTAL_CARR; una
correlación de 0.99. A pesar de esto siguen siendo demasiadas columnas, por lo que aplicaremos la transformación
One Hot sobre los datos restringidos y eliminaremos las columnas que tengan correlación cercana a 1 o a -1.
Una vez determinadas las columnas a utilizar se busca encontrar el mejor algoritmo de clasificación, para lo cual se evaluarán las métricas de los algoritmos KNN, Naive Bayes, Support Vector Machine y Árbol de Decisión. Estas métricas serán evaluadas con la técnica holdout, dejando de los datos para entrenar y aplicando estratificación sobre las particiones, pero, además, se observará el desempeño aplicando subsampling sobre la clase negativa, oversampling sobre la clase positiva y el caso en que no se aplica ninguno, esto al considerar que son pocos los alumnos que se cambian de carrera anualmente.
Por último, usaremos matriz de confusión para observar el desempeño, poniendo especial atención en la métrica recall, dado que no es un gran problema tener falsos positivos, pues lo que se busca es mejorar la información entregada a estudiantes previo a su primera matrícula, considerando quienes tienen un perfil con mayor probabilidad de deserción de su primera carrera.
# df_0to7 corresponde al dataframe con los datos de los años 2010 hasta 2017
# Selección de columnas
sub_df_0to7 = df_0to7[["GEN_ALU", 'cat_periodo', 'anio_ing_carr_ori', 'anio_ing_carr_act', "rango_edad", "tipo_inst_3", "jornada", "tipo_plan_carr", "dur_estudio_carr", "nivel_carrera_1", "nivel_global", "oecd_area", "acreditada_carr", "acreditada_inst"]]
# Restricción a solo datos de pregrado
sub_df_0to7 = (sub_df_0to7.query("nivel_global=='Pregrado' or nivel_global.isnull()")
.drop(columns = ['nivel_global'])
.dropna(subset=['anio_ing_carr_act']))
sub_df_0to7['anio_en_carr_actual'] = sub_df_0to7['anio_ing_carr_act'] - sub_df_0to7['cat_periodo']
# se pide que cat_periodo == anio_ing_carr_act para no contar a una misma persona todos los años
sub_df_0to7['Class'] = sub_df_0to7.apply(lambda row: row.cat_periodo != row.anio_ing_carr_ori and row.cat_periodo == row.anio_ing_carr_act, axis = 1)
sub_df_0to7 = sub_df_0to7.drop(columns = ['anio_ing_carr_ori', 'cat_periodo', 'anio_ing_carr_act'])
sub_df_0to7['acreditada_carr'] = sub_df_0to7['acreditada_carr'].replace('NO ACREDITADA', False, regex=True)
sub_df_0to7['acreditada_carr'] = sub_df_0to7['acreditada_carr'].replace('ACREDITADA', True, regex=True)
sub_df_0to7['acreditada_inst'] = sub_df_0to7['acreditada_inst'].replace('NO ACREDITADA', False, regex=True)
sub_df_0to7['acreditada_inst'] = sub_df_0to7['acreditada_inst'].replace('ACREDITADA', True, regex=True)
Con el fin de analizar la correlación entre columnas, se genera un HeatMap con los datos, el resultado se muestra a continuación, mientras que el código se muestra en la sección Anexos, Implementación, Pregunta 2.
# se eliminan columnas con correlación alta y se eliminan las filas que puedan haber quedado con valores nulos
df_sub_one_hot = df_sub_one_hot.drop(columns = ['tipo_plan_carr_Plan Regular', 'jornada_Diurno', 'acreditada_carr_False']).dropna()
Para analizar el comportamiento con oversampling, subsampling y con los datos
normales se crearon dos funciones basandose en el código del laboratorio 2;
get_data_dict(df, testSize) que genera un diccionario con los conjuntos de testeo y de cada tipo de
entrenamiento, y train(Classifier, data_dict) que recibe el diccionario anterior y un clasificador,
y retorna tres clasificadores entrenados con cada uno de los conjuntos, e imprime sus métricas. Estas funciones
se adjuntan en la sección Anexo, Implementación, Pregunta 2.
Se decide observar, en primera instancia, el rendimiento de los clasificadores al ser entrenados con solo el de los datos, es decir, entradas aproximadamente. Esto por la cantidad de datos que contiene el dataframe completo. Así, para los datos con oversampling en la clase verdadera se cuentan con datos en cada clase y para los datos con subsampling en la clase falsa se tiene datos en cada clase.
Los resultados de las métricas obtenidos para cada clasificador se adjuntan en la tabla siguiente y los códigos en la sección Anexos, Implementación, Pregunta 2.
Notemos que SVM no se pudo terminar de ejecutar pues requiere demasiados recursos.
Se observa que SVM y KNN utilizan muchos recursos de la máquina para tan pocos datos, además, en general las métricas de KNN no presentan una mejora considerable a comparación de Naive Bayes y Árbol de Decisión, y SVM presenta muy malos resultados en especial respecto a la métrica recall de la clase verdadera. Así, se descartan tanto SVM como KNN para entrenar con todos los datos. A partir de aquí se entrenan los clasificadores con el de los datos, lo que implica datos para el caso del oversampling de la clase verdadera y datos para el caso del subsampling sobre la clase falsa.
Los resultados se adjuntan en la tabla siguiente, mientras que el código se adjunta en la sección Anexo, Implementación, Pregunta 2.
Con lo anterior vemos que el clasificador Árbol de Decisión con Oversampling y con Subsampling presenta iguales y mejores métricas, pues si bien Naive Bayes alcanza un recall de , a su vez presenta una precisión demasiado baja, de . Al observar detenidamente las metricas de Árbol de Decisión con Oversampling y con Subsampling vemos una ligera diferencia que nos permite decidir por Árbol de Decisión con Oversampling. Así, hemos obtenido un clasificador capaz de identificar a personas que se cambiarán de carrera, de modo que se pueden implementar medidas para prevenir dicha situación y, de esta manera, ayudar al futuro de los estudiantes.
Esta pregunta está mayormente respondida y diseñada por Erick Perez
La dificultad de esta pregunta radica en definir el concepto de valor y preprocesar los datos de manera favorable, que faciliten el análisis con esto en mente se presenta la siguiente metodología por pasos.
VALOR_ARANCEL,
GEN_ALU,FEC_NAC_ALU, ANIO_ING_CARR_ORI, CAT_PERIODO,
DUR_TOTAL_CARR, ACRE_INS_ANIO, ACRE_INS_DESDE_HASTA. Estas columnas
describen de buena forma las carreras, sus periodos de acreditación y precios, caracterizando también a sus
alumnos. Los datos se manejan en forma de DataFrames de pandas, y realizando un subset de las columnas de
interés.Definir columnas categóricas a utilizar: Se eligen TIPO_INS_2,
NOMB_INST,CINE_F_13_AREA, ACREDITADA_CARR, NIVEL_CARR_2,
REGION_INST. De la misma forma que el punto anterior, se agregan estas columnas al filtrado
quedando un total de 14 columnas, achicando así la cantidad de datos a procesar, recordando que el dataset
original contiene 49 columnas.
Preprocesado: Creación de nuevas columnas para obtener información util.
EDAD_ALU: Edad del estudiante al cual corresponde la matrícula, hace más directo el
análisis de datos, variable numérica.
ANIOS_U: Años que el estudiante lleva en la universidad, hace más directo el filtrado de
datos, variable numérica.
ANIOS_RESTANTES ACRE: Años que restan para que acabe la acreditación de la carrera,
variable numérica.
Preprocesado: Modificación de variables.
GEN_ALU: Se cambia la variable de numérica a categórica.
ACRE_INST_ANIO: Se modifican los valores nan por 0.
Se dejan fuera del análisis las matrículas con valores nan, o irregulares, en alguna columna, que representan menos del 1%.
Se obtienen histogramas de cada una de las variables (o columnas), diferenciando entre cuenta de acreditados y no acreditados, con el fin de analizar singularidades.
Se obtienen métricas estadísticas de los histogramas como media, mediana y desviación estandard.
Se analiza mediante gráficos (matplotlib) la evolución de los estadisticos durante los años desde 2011 al 2018. Adicionalmente se analiza la incorporación de alumnos nuevos a carreras específicas que durante esste tiempo pierdan su acreditación. Lo mismo anterior anallizando el valor de matrícula de estas carreras.
Se realiza clustering (kmeans y herárquico), sumado a metodos de reducción de dimencionalidad (PCA , t-sne y UMAP), para caracterizar y visualizar las particularidades de la acreditación y como se agrupan distintas instituciones y carreras.
Esta pregunta está mayormente respondida y diseñada por Adriana Concha
Siguiendo la sugerencia del cuerpo docente para el Hito 2 y aplicando las nuevas técnicas de minería de datos aprendidas en el curso desde entonces, se decidió responder esta pregunta utilizando Reglas de asociación. En la iteración anterior se propuso utilizar clustering, sin embargo, la búsqueda de reglas de asociación se adapta mejor a la búsqueda de relaciones entre variables. El objetivo de esta pregunta es extraer reglas y relaciones entre la variable valor del arancel y otras variables de las matrículas de educación superior , para poder realizar un análisis sobre éstas.
Propuesta experimental:
Se toma como input los datos para el año 2019, filtrando valores faltantes.
Se seleccionan los atributos: jornada,
rango_edad,dur_total_carr,tipo_inst_3,area_conocimiento,
region_sede, acreditada_inst, valor_arancel,
valor_matricula.
Se categoriza el valor de arancel en tres parámetros:
Se categoriza el valor de la matrícula en tres parámetros:
Se utiliza el algoritmo ECLAT para obtener los itemsets más frecuentes, con support sobre 4%.
Se utiliza el algoritmo apriori para generar reglas de asociación sobre los itemsets más frecuentes. Específicamente, se buscan reglas de asociación con cada categoría de Arancel en el consecuente. Se utiliza el parámetro minlen igual a 2, para encontrar reglas de al menos 2 elementos.
Se utiliza como validación las métricas support sobre 4% y confidence sobre 30%. Además, se ordenan las reglas generadas de acuerdo a su lift, para conocer la efectividad de las predicciones. Para esta pregunta, nos interesan aquellas reglas con lift superior a 1.
A partir de los resultados obtenidos, se generan las siguientes visualizaciones:
La implementación en detalle de esta pregunta se puede ver en Anexos, Implementación, Pregunta 4. Se utilizaron 1268504 registros para el año 2019, añadiendo las categorías para valor de arancel y de matrícula.
| jornada | rango_edad | dur_total_carr | tipo_inst_3 | area_conocimiento | region_sede | acreditada_inst | Categoria_arancel | Categoria_matricula |
|---|---|---|---|---|---|---|---|---|
| Diurno | 15 a 19 años | 10 | Universidades Privadas | Salud | Coquimbo | ACREDITADA | AM | MA |
| Diurno | 20 a 24 años | 10 | Universidades Estatales CRUCH | Ciencias Sociales | Metropolitana | ACREDITADA | AA | MM |
| Diurno | 25 a 29 años | 10 | Universidades Privadas CRUCH | Humanidades | Metropolitana | ACREDITADA | AA | MB |
| Vespertino | 15 a 19 años | 5 | Institutos Profesionales | Administración y Comercio | Metropolitana | NO ACREDITADA | AB | MB |
| Vespertino | 20 a 24 años | 5 | Institutos Profesionales | Administración y Comercio | Metropolitana | ACREDITADA | AB | MM |
| Diurno | 20 a 24 años | 10 | Universidades Estatales CRUCH | Tecnología | Metropolitana | ACREDITADA | AA | MM |
Se obtuvieron los siguientes items más frecuentes con el algoritmo ECLAT.
| items | support | count |
|---|---|---|
| {ACREDITADA} | 0.93 | 1174652 |
| {Diurno} | 0.70 | 892899 |
| {ACREDITADA,Diurno} | 0.68 | 860341 |
| {Metropolitana} | 0.48 | 613381 |
| {20 a 24 años} | 0.47 | 598695 |
| {20 a 24 años,ACREDITADA} | 0.46 | 578644 |
Utilizando el algoritmo APRIORI se generaron 8484 reglas, con support mayor a 4% y confidence mayor a 30%. Como se observa en el gráfico de dispersión, la mayoría de las reglas poseen un support menor al 20%.
Dentro de las reglas generadas, se identificaron las siguientes reglas que llevan como consecuente a un Arancel Alto. Por ejemplo, de esto se puede concluir con un 4% de support y 92% de confidence, que una matrícula en una Universidad Privada, Acreditada, Diurna, en el área de la Salud con una Matrícula alta, lleva a tener un Arancel Alto. Esto con un lift de 2.76.
| rules | support | confidence | coverage | lift | count |
|---|---|---|---|---|---|
| {ACREDITADA,Diurno,MA,Salud,Universidades Privadas} => {AA} | 0.04 | 0.92 | 0.05 | 2.76 | 56737 |
| {Diurno,MA,Salud,Universidades Privadas} => {AA} | 0.05 | 0.92 | 0.05 | 2.75 | 58413 |
| {10,ACREDITADA,Diurno,MA,Metropolitana} => {AA} | 0.05 | 0.91 | 0.06 | 2.73 | 66365 |
| {ACREDITADA,MA,Salud,Universidades Privadas} => {AA} | 0.05 | 0.91 | 0.05 | 2.73 | 57557 |
| {10,ACREDITADA,MA,Metropolitana} => {AA} | 0.05 | 0.91 | 0.06 | 2.72 | 69277 |
| {10,ACREDITADA,Diurno,MA,Metropolitana,Universidades Privadas} => {AA} | 0.04 | 0.90 | 0.05 | 2.70 | 55948 |
Por otra parte, se identificaron las siguientes reglas que implican un Arancel Bajo. Por ejemplo, con un lift de 3, support 4% y confidence 100%, se puede concluir que una matrícula en una carrera de 5 años, en un Instituto Profesional con matrícula baja, implicará un Arancel Bajo.
| rules | support | confidence | coverage | lift | count |
|---|---|---|---|---|---|
| {5,Institutos Profesionales,MB} => {AB} | 0.04 | 1.00 | 0.04 | 3.00 | 54192 |
| {5,Centros de Formación Técnica,MB} => {AB} | 0.05 | 0.99 | 0.05 | 2.97 | 63287 |
| {5,ACREDITADA,Centros de Formación Técnica,MB} => {AB} | 0.04 | 0.99 | 0.04 | 2.97 | 55721 |
| {5,Diurno,MB} => {AB} | 0.05 | 0.99 | 0.05 | 2.97 | 62959 |
| {5,ACREDITADA,Diurno,MB} => {AB} | 0.04 | 0.99 | 0.04 | 2.96 | 54118 |
| {5,MB} => {AB} | 0.10 | 0.98 | 0.11 | 2.96 | 131416 |
En la siguiente visualización, se pueden ver las relaciones entre las Top 50 reglas generadas, con mayor lift, para consecuente Arancel Bajo. Se observa que los mayores lift se obtienen a partir de precedentes Área: Administración y Comercio, Matrícula baja y Centros de formación técnica. Los métodos A Distancia, a pesar de su bajo support, también presentan un lift alto para generar Arancel Bajo.
Así, se logró identificar cómo la variables acreditación, tipo de institución, duración de carrera y área de conocimiento influyen en el valor del arancel. Por ejemplo, con 92% de confianza, se puede decir que una carrera acreditada del área de la salud en la Región Metropolitana implica un arancel alto. Por otra parte, con 100% de confianza una carrera de 5 años en un Instituto Profesional implica un Arancel Bajo. Cabe destacar que las principales reglas de asociación obtenidas con consecuente una categoría de valor de arancel, poseen lift superiores a 1, por lo que se concluye que la ocurrencia de los valores de los precedentes influyen positivamente en la valorización del arancel.
Gracias a todo lo ya mencionado se logró responder a las preguntas iniciales, obteniendo información relevante a través de la minería de datos. Entre los aportes se destaca el reconocimiento de la obtención de un clasificador que permite conocer si un alumno cambiará de carrera, junto a la identificación de las principales variables influyentes en el valor del arancel, y []. Todo esto permite caracterizar la educación superior en Chile y, más aún, otorga información trascendental para avanzar en mejoras que ayuden a quienes busquen continuar sus estudios en la educación superior.
Por otro lado, analizando el desarrollo del proyecto, consideramos que las herramientas entregadas en el curso fueron de gran utilidad
Si bien se lograron conclusiones importantes, esto no implica que no exista margen de mejora. Así, como desafío a futuro, se espera analizar nuevamente la relación entre las variables estudiadas, a través de los años, considerando también cómo se relaciona la modalidad remota con el valor de arancel para los años 2020 y 2021.
Descripción del dataset dado por el Mineduc aquí.
Con el fin de limpiar los datos se utiliza el código siguiente:
import numpy as np
#dfX corresponde al dataframe con los datos del año X
d = [df0, df1, df2, df3, df4, df5, df6, df7, df8, df9]
for i in range(len(d)):
print(i)
d[i] = d[i].replace(r'^\s+$', np.nan, regex=True)
d[i]["anio_ing_carr_act"] = d[i]["anio_ing_carr_act"].replace(9995, np.nan, regex=True)
d[i]["anio_ing_carr_act"] = d[i]["anio_ing_carr_act"].replace(0, np.nan, regex=True)
d[i]["anio_ing_carr_ori"] = d[i]["anio_ing_carr_ori"].replace(9995, np.nan, regex=True)
d[i]["FEC_NAC_ALU"] = d[i]["FEC_NAC_ALU"].replace("190001", np.nan, regex=True)
d[i]["FEC_NAC_ALU"] = d[i]["FEC_NAC_ALU"].replace(190001, np.nan, regex=True)
d[i] = d[i].replace("SIN INFORMACION", np.nan, regex=True)
d[i][["valor_arancel"]] = d[i][["valor_arancel"]].astype(np.float64)
name = f'{2010+i}'
d[i].to_csv(name+'.csv',index=False)
A continuación se muestra el código utilizado para obtener los gráficos relativos a la cantidad de datos anuales y al porcentaje de datos nulos en cada año.
d = [df0, df1, df2, df3, df4, df5, df6, df7, df8, df9]
nulos, l, l_total, anno, porcentaje = [], [], [], [], []
i = 2010
for df in d:
n = 0
for v in list(df.isnull().sum()):
n += v
anno.append(i)
nulos.append(n)
t = len(df)*len(list(df))*1.0
l.append(len(df))
porcentaje.append((n/t)*100)
i+=1
import matplotlib.pyplot as plt
import numpy as np
plt.rcParams['figure.figsize'] = [11, 5.5]
fig_total_datos = plt.figure()
fig_total_datos.clf()
ax_total_datos = fig_total_datos.add_subplot(111)
#ax_total_datos.bar(anno, l, align='center', alpha=0.7, color = 'darkorange', label = "Entradas en la tabla")
ax_total_datos.plot(anno, l, alpha=1, color = '#00d4f0', label = "Entradas en la tabla")
ax_total_datos.plot(anno, l, 'o', alpha=1, color = '#071554', label = "Entradas en la tabla")
ax_total_datos.set_ylabel("Total de datos")
ax_total_datos.set_xlabel("Año de los datos")
ax_total_datos.set_title("Cantidad de datos recolectados para cada año")
#set off Scientific notation from Y-axis
ax_total_datos.get_yaxis().get_major_formatter().set_useOffset(False)
ax_total_datos.get_yaxis().get_major_formatter().set_scientific(False)
#ax_total_datos.legend(loc="best")
fig_total_datos.savefig("total_datos.png", transparent=False)
fig_total_datos.show()
fig_porcentaje_nulo = plt.figure()
fig_porcentaje_nulo.clf()
ax_porcentaje_nulo = fig_porcentaje_nulo.add_subplot(111)
graph = ax_porcentaje_nulo.bar(anno, porcentaje, align='center', color = '#071554', label = "Porcentaje de datos nulos")
ax_porcentaje_nulo.bar([2016], [14], align='center', alpha=0)
ax_porcentaje_nulo.set_ylabel("Porcentaje respecto al total de datos")
ax_porcentaje_nulo.set_xlabel("Año de los datos")
ax_porcentaje_nulo.set_title("Porcentaje de datos nulos en los datos recolectados para cada año")
#fig_porcentaje_nulo.legend(loc="upper left")
i = 0
for p in graph:
width = p.get_width()
height = p.get_height()
x, y = p.get_xy()
num = str(porcentaje[i]).split(".")
t = num[0] +'.' + num[1][:2]+'%'
plt.text(x+width/2,
y+0.5+height*1,
t,
ha='center')
#weight='bold')
i+=1
fig_porcentaje_nulo.savefig("porcentaje_datos_nulos.png", transparent=False)
fig_porcentaje_nulo.show()
Para entender mejor los datos se observan las columnas de cada
import pandas as pd
# df5 corresponde al DataFrame de Pandas en donde se cargaron los datos del año 2015
df5.info()
<class 'pandas.core.frame.DataFrame'> RangeIndex: 1233043 entries, 0 to 1233042 Data columns (total 48 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 cat_periodo 1233043 non-null int64 1 codigo_unico 1233043 non-null object 2 MRUN 1231802 non-null float64 3 GEN_ALU 1233043 non-null int64 4 FEC_NAC_ALU 1232951 non-null float64 5 rango_edad 1232914 non-null object 6 anio_ing_carr_ori 1233043 non-null int64 7 sem_ing_carr_ori 1233043 non-null int64 8 anio_ing_carr_act 317310 non-null float64 9 sem_ing_carr_act 316056 non-null float64 10 tipo_inst_1 1233043 non-null object 11 tipo_inst_2 1233043 non-null object 12 tipo_inst_3 1233043 non-null object 13 cod_inst 1233043 non-null int64 14 nomb_inst 1233043 non-null object 15 cod_sede 1233018 non-null float64 16 nomb_sede 1233043 non-null object 17 cod_carrera 1217385 non-null float64 18 nomb_carrera 1233043 non-null object 19 modalidad 1233043 non-null object 20 jornada 1233043 non-null object 21 version 1217385 non-null float64 22 tipo_plan_carr 1233043 non-null object 23 dur_estudio_carr 1233043 non-null int64 24 dur_proceso_tit 1233011 non-null float64 25 dur_total_carr 1233043 non-null int64 26 region_sede 1233043 non-null object 27 provincia_sede 1233043 non-null object 28 comuna_sede 1233043 non-null object 29 nivel_global 1233043 non-null object 30 nivel_carrera_1 1233043 non-null object 31 nivel_carrera_2 1233043 non-null object 32 requisito_ingreso 1190760 non-null object 33 vigencia_carrera 1233043 non-null object 34 valor_matricula 1230980 non-null float64 35 valor_arancel 1224968 non-null float64 36 codigo_demre 374549 non-null float64 37 area_conocimiento 1233043 non-null object 38 oecd_area 1233043 non-null object 39 oecd_subarea 1233043 non-null object 40 area_carrera_generica 1233043 non-null object 41 acreditada_carr 1233043 non-null object 42 acreditada_inst 1233043 non-null object 43 acre_inst_desde_hasta 1096169 non-null object 44 acre_inst_anio 1096169 non-null float64 45 costo_proceso_titulacion 1013291 non-null object 46 costo_obtencion_titulo_diploma 913226 non-null object 47 costo_tit_explicacion_observacion 682011 non-null object dtypes: float64(12), int64(7), object(29) memory usage: 451.6+ MB
df5.describe()
| cat_periodo | MRUN | GEN_ALU | FEC_NAC_ALU | anio_ing_carr_ori | sem_ing_carr_ori | anio_ing_carr_act | sem_ing_carr_act | cod_inst | cod_sede | cod_carrera | version | dur_estudio_carr | dur_proceso_tit | dur_total_carr | valor_matricula | valor_arancel | codigo_demre | acre_inst_anio | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| count | 1233043.0 | 1.231802e+06 | 1.233043e+06 | 1.232951e+06 | 1.233043e+06 | 1.233043e+06 | 317310.000000 | 316056.000000 | 1.233043e+06 | 1.233018e+06 | 1.217385e+06 | 1.217385e+06 | 1.233043e+06 | 1.233011e+06 | 1.233043e+06 | 1.230980e+06 | 1.224968e+06 | 374549.000000 | 1.096169e+06 |
| mean | 2015.0 | 1.250176e+07 | 1.519321e+00 | 1.989944e+05 | 2.638130e+03 | 1.032717e+00 | 1931.152702 | 1.004714 | 1.141274e+02 | 7.013445e+00 | 9.538939e+01 | 1.086465e+00 | 7.691002e+00 | 7.191379e-01 | 7.800515e+00 | 1.598656e+05 | 2.312080e+06 | 25826.509111 | 4.626894e+00 |
| std | 0.0 | 7.221055e+06 | 4.996268e-01 | 6.612891e+02 | 2.144596e+03 | 1.778961e-01 | 399.460012 | 0.294755 | 1.114369e+02 | 9.289754e+00 | 1.230071e+02 | 3.161982e-01 | 2.717349e+00 | 1.075862e+00 | 2.687532e+00 | 1.153825e+05 | 1.341378e+06 | 11764.667756 | 1.480553e+00 |
| min | 2015.0 | 5.000000e+00 | 1.000000e+00 | 1.917040e+05 | 1.970000e+03 | 1.000000e+00 | 0.000000 | 0.000000 | 1.000000e+00 | 0.000000e+00 | 0.000000e+00 | 1.000000e+00 | 1.000000e+00 | 0.000000e+00 | 1.000000e+00 | 0.000000e+00 | 4.500000e+04 | 1710.000000 | 2.000000e+00 |
| 25% | 2015.0 | 6.242432e+06 | 1.000000e+00 | 1.988060e+05 | 2.012000e+03 | 1.000000e+00 | 2013.000000 | 1.000000 | 4.600000e+01 | 1.000000e+00 | 2.100000e+01 | 1.000000e+00 | 5.000000e+00 | 0.000000e+00 | 5.000000e+00 | 9.950000e+04 | 1.360000e+06 | 15098.000000 | 3.000000e+00 |
| 50% | 2015.0 | 1.250127e+07 | 2.000000e+00 | 1.992050e+05 | 2.014000e+03 | 1.000000e+00 | 2014.000000 | 1.000000 | 8.800000e+01 | 2.000000e+00 | 4.800000e+01 | 1.000000e+00 | 8.000000e+00 | 1.000000e+00 | 8.000000e+00 | 1.300000e+05 | 1.870000e+06 | 23068.000000 | 5.000000e+00 |
| 75% | 2015.0 | 1.875779e+07 | 2.000000e+00 | 1.994100e+05 | 2.015000e+03 | 1.000000e+00 | 2015.000000 | 1.000000 | 1.320000e+02 | 9.000000e+00 | 1.200000e+02 | 1.000000e+00 | 1.000000e+01 | 1.000000e+00 | 1.000000e+01 | 1.950000e+05 | 3.012100e+06 | 38173.000000 | 6.000000e+00 |
| max | 2015.0 | 2.512886e+07 | 2.000000e+00 | 2.009020e+05 | 9.999000e+03 | 2.000000e+00 | 9999.000000 | 2.000000 | 7.820000e+02 | 5.000000e+01 | 8.640000e+02 | 7.000000e+00 | 2.400000e+01 | 1.200000e+01 | 2.400000e+01 | 2.459445e+06 | 3.300000e+07 | 45041.000000 | 7.000000e+00 |
df5.head(n=20)
| cat_periodo | codigo_unico | MRUN | GEN_ALU | FEC_NAC_ALU | rango_edad | anio_ing_carr_ori | sem_ing_carr_ori | anio_ing_carr_act | sem_ing_carr_act | ... | oecd_area | oecd_subarea | area_carrera_generica | acreditada_carr | acreditada_inst | acre_inst_desde_hasta | acre_inst_anio | costo_proceso_titulacion | costo_obtencion_titulo_diploma | costo_tit_explicacion_observacion | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 2015 | I4S9C53J1V1 | NaN | 2 | 199303.0 | 20 a 24 años | 2015 | 1 | NaN | NaN | ... | Ciencias Sociales, Enseñanza Comercial y Derecho | Enseñanza Comercial y Administración | Publicidad | NO ACREDITADA | ACREDITADA | 20/12/2014 - 20/12/2017 | 3.0 | 0 | 0 | NaN |
| 1 | 2015 | I4S9C14J2V1 | NaN | 2 | 199509.0 | 15 a 19 años | 2015 | 1 | NaN | NaN | ... | Ciencias Sociales, Enseñanza Comercial y Derecho | Enseñanza Comercial y Administración | Administración de Empresas e Ing. Asociadas | ACREDITADA | ACREDITADA | 20/12/2014 - 20/12/2017 | 3.0 | 329850 | 0 | NaN |
| 2 | 2015 | I9S2C7J1V1 | NaN | 1 | 199306.0 | 20 a 24 años | 2015 | 1 | NaN | NaN | ... | Ciencias Sociales, Enseñanza Comercial y Derecho | Ciencias Sociales y del Comportamiento | Psicología | NO ACREDITADA | NO ACREDITADA | NaN | NaN | 262737 | 50000 | MATRICULA Y DEFENSA PROYECTO DE TITULO |
| 3 | 2015 | I9S2C1J2V1 | NaN | 2 | 197810.0 | 35 a 39 años | 2015 | 1 | NaN | NaN | ... | Ciencias Sociales, Enseñanza Comercial y Derecho | Enseñanza Comercial y Administración | Ingeniería Comercial | NO ACREDITADA | NO ACREDITADA | NaN | NaN | 632078 | 50000 | MATRICULA, TRABAJO PROYECTO DE TITULO Y DEFENS... |
| 4 | 2015 | I10S5C297J1V1 | NaN | 2 | 199103.0 | 20 a 24 años | 2015 | 1 | NaN | NaN | ... | Humanidades y Artes | Artes | Diseño | NO ACREDITADA | ACREDITADA | 20/05/2015 - 20/05/2020 | 5.0 | 154945 | 0 | NaN |
| 5 | 2015 | I10S5C183J1V1 | NaN | 1 | 199003.0 | 25 a 29 años | 2015 | 1 | NaN | NaN | ... | Ingeniería, Industria y Construcción | Arquitectura y Construcción | Arquitectura | NO ACREDITADA | ACREDITADA | 20/05/2015 - 20/05/2020 | 5.0 | 154945 | 0 | NaN |
| 6 | 2015 | I13S3C2J2V1 | NaN | 2 | 199309.0 | 20 a 24 años | 2015 | 1 | NaN | NaN | ... | Ciencias Sociales, Enseñanza Comercial y Derecho | Enseñanza Comercial y Administración | Ingeniería Comercial | ACREDITADA | ACREDITADA | 08/12/2014 - 08/12/2017 | 3.0 | 0 | 110000 | LAS ACTIVIDADES DE TITULACION SON PARTE DEL PL... |
| 7 | 2015 | I13S1C10J2V1 | NaN | 2 | 199409.0 | 20 a 24 años | 2013 | 1 | NaN | NaN | ... | Ciencias Sociales, Enseñanza Comercial y Derecho | Enseñanza Comercial y Administración | Relaciones Públicas | ACREDITADA | ACREDITADA | 08/12/2014 - 08/12/2017 | 3.0 | 0 | 110000 | LAS ACTIVIDADES DE TITULACION SON PARTE DEL PL... |
| 8 | 2015 | I16S27C27J2V1 | NaN | 1 | 197909.0 | 35 a 39 años | 9999 | 1 | 2013.0 | 1.0 | ... | Ciencias Sociales, Enseñanza Comercial y Derecho | Enseñanza Comercial y Administración | Ingeniería Comercial | NO ACREDITADA | NO ACREDITADA | NaN | NaN | 203500 | 305000 | DERECHO POR EXAMEN DE GRADO DE LICENCIATURA $2... |
| 9 | 2015 | I16S27C27J2V1 | NaN | 2 | 198901.0 | 25 a 29 años | 9999 | 1 | 2013.0 | 1.0 | ... | Ciencias Sociales, Enseñanza Comercial y Derecho | Enseñanza Comercial y Administración | Ingeniería Comercial | NO ACREDITADA | NO ACREDITADA | NaN | NaN | 203500 | 305000 | DERECHO POR EXAMEN DE GRADO DE LICENCIATURA $2... |
| 10 | 2015 | I16S27C27J2V1 | NaN | 2 | 198303.0 | 30 a 34 años | 9999 | 1 | 2013.0 | 1.0 | ... | Ciencias Sociales, Enseñanza Comercial y Derecho | Enseñanza Comercial y Administración | Ingeniería Comercial | NO ACREDITADA | NO ACREDITADA | NaN | NaN | 203500 | 305000 | DERECHO POR EXAMEN DE GRADO DE LICENCIATURA $2... |
| 11 | 2015 | I16S27C27J2V1 | NaN | 2 | 198612.0 | 25 a 29 años | 9999 | 1 | 2013.0 | 1.0 | ... | Ciencias Sociales, Enseñanza Comercial y Derecho | Enseñanza Comercial y Administración | Ingeniería Comercial | NO ACREDITADA | NO ACREDITADA | NaN | NaN | 203500 | 305000 | DERECHO POR EXAMEN DE GRADO DE LICENCIATURA $2... |
| 12 | 2015 | I16S27C27J2V1 | NaN | 1 | 198612.0 | 25 a 29 años | 9999 | 1 | 2013.0 | 1.0 | ... | Ciencias Sociales, Enseñanza Comercial y Derecho | Enseñanza Comercial y Administración | Ingeniería Comercial | NO ACREDITADA | NO ACREDITADA | NaN | NaN | 203500 | 305000 | DERECHO POR EXAMEN DE GRADO DE LICENCIATURA $2... |
| 13 | 2015 | I16S27C27J2V1 | NaN | 2 | 198807.0 | 25 a 29 años | 9999 | 1 | 2013.0 | 1.0 | ... | Ciencias Sociales, Enseñanza Comercial y Derecho | Enseñanza Comercial y Administración | Ingeniería Comercial | NO ACREDITADA | NO ACREDITADA | NaN | NaN | 203500 | 305000 | DERECHO POR EXAMEN DE GRADO DE LICENCIATURA $2... |
| 14 | 2015 | I16S27C27J2V1 | NaN | 2 | 198506.0 | 30 a 34 años | 9999 | 1 | 2013.0 | 1.0 | ... | Ciencias Sociales, Enseñanza Comercial y Derecho | Enseñanza Comercial y Administración | Ingeniería Comercial | NO ACREDITADA | NO ACREDITADA | NaN | NaN | 203500 | 305000 | DERECHO POR EXAMEN DE GRADO DE LICENCIATURA $2... |
| 15 | 2015 | I16S27C27J2V1 | NaN | 1 | 198907.0 | 25 a 29 años | 9999 | 1 | 2013.0 | 1.0 | ... | Ciencias Sociales, Enseñanza Comercial y Derecho | Enseñanza Comercial y Administración | Ingeniería Comercial | NO ACREDITADA | NO ACREDITADA | NaN | NaN | 203500 | 305000 | DERECHO POR EXAMEN DE GRADO DE LICENCIATURA $2... |
| 16 | 2015 | I16S27C27J2V1 | NaN | 2 | 198411.0 | 30 a 34 años | 9999 | 1 | 2013.0 | 1.0 | ... | Ciencias Sociales, Enseñanza Comercial y Derecho | Enseñanza Comercial y Administración | Ingeniería Comercial | NO ACREDITADA | NO ACREDITADA | NaN | NaN | 203500 | 305000 | DERECHO POR EXAMEN DE GRADO DE LICENCIATURA $2... |
| 17 | 2015 | I16S27C27J2V1 | NaN | 2 | 198507.0 | 25 a 29 años | 9999 | 1 | 2013.0 | 1.0 | ... | Ciencias Sociales, Enseñanza Comercial y Derecho | Enseñanza Comercial y Administración | Ingeniería Comercial | NO ACREDITADA | NO ACREDITADA | NaN | NaN | 203500 | 305000 | DERECHO POR EXAMEN DE GRADO DE LICENCIATURA $2... |
| 18 | 2015 | I16S27C27J2V1 | NaN | 2 | 197912.0 | 35 a 39 años | 9999 | 1 | 2013.0 | 1.0 | ... | Ciencias Sociales, Enseñanza Comercial y Derecho | Enseñanza Comercial y Administración | Ingeniería Comercial | NO ACREDITADA | NO ACREDITADA | NaN | NaN | 203500 | 305000 | DERECHO POR EXAMEN DE GRADO DE LICENCIATURA $2... |
| 19 | 2015 | I16S27C27J2V1 | NaN | 1 | 196303.0 | 40 y más años | 9999 | 1 | 2013.0 | 1.0 | ... | Ciencias Sociales, Enseñanza Comercial y Derecho | Enseñanza Comercial y Administración | Ingeniería Comercial | NO ACREDITADA | NO ACREDITADA | NaN | NaN | 203500 | 305000 | DERECHO POR EXAMEN DE GRADO DE LICENCIATURA $2... |
20 rows × 48 columns
for col in list(df5):
print(df5[[col]].drop_duplicates())
cat_periodo
0 2015
codigo_unico
0 I4S9C53J1V1
1 I4S9C14J2V1
2 I9S2C7J1V1
3 I9S2C1J2V1
4 I10S5C297J1V1
... ...
1229177 I165S14C44J5V1
1231842 I165S6C15J2V1
1232557 I9M2015N1
1232774 I46M2015N14
1232779 I46M2015N16
[14788 rows x 1 columns]
MRUN
0 NaN
1241 5.0
1242 37.0
1243 42.0
1244 43.0
... ...
1233038 25128853.0
1233039 25128854.0
1233040 25128855.0
1233041 25128856.0
1233042 25128857.0
[1220760 rows x 1 columns]
GEN_ALU
0 2
2 1
FEC_NAC_ALU
0 199303.0
1 199509.0
2 199306.0
3 197810.0
4 199103.0
... ...
1169370 200005.0
1178602 200107.0
1207632 193704.0
1221455 194509.0
1232738 199904.0
[749 rows x 1 columns]
rango_edad
0 20 a 24 años
1 15 a 19 años
3 35 a 39 años
5 25 a 29 años
10 30 a 34 años
19 40 y más años
32 NaN
anio_ing_carr_ori
0 2015
7 2013
8 9999
32 2014
37 2012
92 9998
126 2011
128 2005
523 2010
526 2008
697 2006
841 2009
1324 2007
1490 1998
2341 2004
4800 1995
7901 2000
8173 2002
8714 1997
9161 2001
11099 1990
14819 1999
15263 1981
16203 2003
21917 1994
30232 1992
32894 1987
49785 1991
55523 1988
68665 1993
112363 1982
118847 1996
146168 1986
254592 1984
281156 1989
310007 1983
316693 1970
650397 1979
sem_ing_carr_ori
0 1
36 2
anio_ing_carr_act
0 NaN
8 2013.0
71 2015.0
119 2014.0
858 2012.0
1239 0.0
1244 2010.0
1313 2005.0
1329 2011.0
1352 2008.0
2172 2009.0
2518 2006.0
2889 2007.0
5531 2004.0
8173 2002.0
9161 2001.0
10101 1996.0
11099 1990.0
22220 2003.0
27599 1994.0
30232 1992.0
32650 2000.0
33942 1995.0
38103 1999.0
131973 1993.0
141880 1998.0
232949 9999.0
336527 1997.0
500658 1991.0
591192 1988.0
609084 1987.0
756506 1989.0
sem_ing_carr_act
0 NaN
8 1.0
1239 0.0
1314 2.0
tipo_inst_1
0 Universidades
139 Institutos Profesionales
185 Centros de Formación Técnica
tipo_inst_2
0 Universidades Privadas
103 Universidades CRUCH
139 Institutos Profesionales
185 Centros de Formación Técnica
tipo_inst_3
0 Universidades Privadas
103 Universidades Estatales CRUCH
127 Universidades Privadas CRUCH
139 Institutos Profesionales
185 Centros de Formación Técnica
cod_inst
0 4
2 9
4 10
6 13
8 16
... ...
44635 399
66997 109
73952 119
92286 326
409830 754
[156 rows x 1 columns]
nomb_inst
0 UNIVERSIDAD CENTRAL DE CHILE
2 UNIVERSIDAD PEDRO DE VALDIVIA
4 UNIVERSIDAD MAYOR
6 UNIVERSIDAD SANTO TOMAS
8 UNIVERSIDAD LA REPUBLICA
... ...
44635 CFT CEPONAL
66997 IP ADVENTISTA
73952 IP ALEMAN WILHELM VON HUMBOLDT
92286 CFT CROWNLIET
409830 IP ESCUELA DE MARINA MERCANTE PILOTO PARDO
[156 rows x 1 columns]
cod_sede
0 9.0
2 2.0
4 5.0
6 3.0
7 1.0
8 27.0
67 4.0
75 8.0
77 7.0
78 6.0
92 32.0
95 25.0
97 24.0
98 21.0
99 13.0
154 38.0
155 33.0
156 19.0
157 16.0
158 15.0
164 14.0
167 10.0
178 23.0
179 17.0
187 41.0
227 37.0
229 36.0
233 30.0
1246 12.0
1250 44.0
1356 50.0
1368 35.0
1398 11.0
1403 31.0
1418 18.0
1440 40.0
1474 42.0
1476 26.0
1488 20.0
1500 29.0
1516 0.0
1534 47.0
1552 39.0
1591 28.0
1637 34.0
1663 49.0
1705 22.0
1880 43.0
2210 45.0
7726 NaN
nomb_sede
0 SUB-CAMPUS ALMAGRO NORTE
2 SEDE LA SERENA
4 SEDE DEL CLAUSTRO
6 SEDE IQUIQUE
7 CASA CENTRAL (SANTIAGO)
... ...
249705 CENTRO DE EXTENSION
311823 SEDE CURACAUTIN
330817 SEDE FUTRONO
346868 SEDE CASABLANCA
409830 VALPARAISO
[189 rows x 1 columns]
cod_carrera
0 53.0
1 14.0
2 7.0
3 1.0
4 297.0
... ...
862020 784.0
983633 626.0
1035412 781.0
1066415 838.0
1205505 624.0
[800 rows x 1 columns]
nomb_carrera
0 PUBLICIDAD
1 INGENIERIA DE EJECUCION EN ADMINISTRACION DE N...
2 PSICOLOGIA
3 INGENIERIA COMERCIAL
4 DISEÑO MENCION INDUSTRIAL/GRAFICO/AMBIENTES
... ...
1213925 LICENCIATURA EN LETRAS, MENCION FRANCES
1216910 ESPECIALIDAD EN NEONATOLOGIA
1219487 MAGISTER EN GEOGRAFIA, MENCIONES
1220403 POSTITULO EN MEDICINA REPRODUCTIVA
1232774 MAGISTER EN CURRICULUM Y EVALUACION EDUCACIONAL
[4489 rows x 1 columns]
modalidad
0 Presencial
222 Semipresencial
254 No Presencial
jornada
0 Diurno
1 Vespertino
254 A Distancia
274 Otro
279 Semipresencial
version
0 1.0
54 2.0
235 3.0
487 NaN
1775 7.0
4087 4.0
6500 5.0
57518 6.0
tipo_plan_carr
0 Plan Regular
8 Plan Regular de Continuidad
279 Plan Especial
dur_estudio_carr
0 8
2 10
5 11
8 5
29 6
34 12
54 9
100 2
120 14
185 4
262 1
277 3
1195 7
5438 20
17154 24
109083 16
dur_proceso_tit
0 0.0
2 2.0
3 1.0
8 5.0
29 6.0
414 3.0
526 4.0
1380 12.0
1482 10.0
1488 9.0
2816 11.0
3823 8.0
4342 7.0
78148 NaN
dur_total_carr
0 8
2 10
5 11
8 5
29 6
34 12
54 9
100 2
120 14
186 4
262 1
277 3
1693 7
2108 13
5438 20
17154 24
109083 16
region_sede
0 Metropolitana
2 Coquimbo
6 Tarapacá
8 Arica y Parinacota
32 Valparaíso
63 Ñuble
71 Antofagasta
78 Atacama
99 Biobío
187 Lib. Gral B. O'Higgins
950 La Araucanía
951 Maule
1239 Los Lagos
1250 Magallanes
1294 Los Ríos
1604 Aysén
provincia_sede
0 SANTIAGO
2 ELQUI
6 IQUIQUE
8 ARICA
32 VALPARAISO
63 DIGUILLIN
71 EL LOA
78 COPIAPO
79 ANTOFAGASTA
99 CONCEPCION
187 CACHAPOAL
227 CORDILLERA
950 CAUTIN
951 TALCA
1235 CURICO
1239 LLANQUIHUE
1250 MAGALLANES
1257 LINARES
1258 OSORNO
1270 LIMARI
1278 BIOBIO
1294 VALDIVIA
1336 MAIPO
1400 MALLECO
1441 LOS ANDES
1464 MELIPILLA
1581 PETORCA
1604 COYHAIQUE
1608 SAN FELIPE DE ACONCAGUA
1619 QUILLOTA
1717 CHILOE
1806 ARAUCO
1845 SAN ANTONIO
1887 CHOAPA
2029 CAUQUENES
2248 HUASCO
2317 COLCHAGUA
3070 CHACABUCO
6351 TIERRA DEL FUEGO
8430 DEL RANCO
12038 TOCOPILLA
12213 ULTIMA ESPERANZA
comuna_sede
0 SANTIAGO
2 LA SERENA
6 IQUIQUE
8 ARICA
32 VIÑA DEL MAR
... ...
92728 PAILLACO
212480 LO PRADO
311823 CURACAUTIN
330817 FUTRONO
346868 CASABLANCA
[92 rows x 1 columns]
nivel_global
0 Pregrado
254 Postgrado
260 Postítulo
nivel_carrera_1
0 Profesional Con Licenciatura
44 Licenciatura No Conducente a Título
56 Bachillerato, Ciclo Inicial o Plan Común
71 Técnico de Nivel Superior
75 Profesional Sin Licenciatura
254 Magister
260 Diplomado (superior a un semestre)
270 Doctorado
463 Especialidad Médica U Odontológica
496 Postítulo
nivel_carrera_2
0 Carreras Profesionales
71 Carreras Técnicas
254 Magister
260 Postítulo
270 Doctorado
requisito_ingreso
0 Educación Media
8 Licenciatura
124 NaN
254 Título Profesional
283 Técnico de Nivel Superior
414 Magíster
871 Especialidad Médica u Odontológica
1313 Plan Común
1367 Ciclo Básico
48901 Postítulo
60305 Bachillerato
vigencia_carrera
0 VIGENTE CON ALUMNOS NUEVOS
31 VIGENTE SIN ALUMNOS NUEVOS
valor_matricula
0 100000.0
2 120000.0
4 363900.0
5 369800.0
6 102000.0
... ...
860116 188147.0
953173 135673.0
955465 256200.0
1075378 493740.0
1114815 137570.0
[523 rows x 1 columns]
valor_arancel
0 3369000.0
1 2312000.0
2 2185000.0
3 1760000.0
4 3900530.0
... ...
1130168 2221000.0
1148014 3074306.0
1165661 375000.0
1171166 388500.0
1227859 1354381.0
[3299 rows x 1 columns]
codigo_demre
0 NaN
4 39108.0
5 39103.0
32 41064.0
33 41136.0
... ...
851149 23023.0
857550 1747.0
870770 1810.0
913587 1748.0
1092272 1799.0
[1562 rows x 1 columns]
area_conocimiento
0 Ciencias Sociales
1 Administración y Comercio
4 Arte y Arquitectura
29 Tecnología
35 Salud
44 Ciencias Básicas
48 Agropecuaria
66 Educación
100 Humanidades
277 Derecho
149294 Sin área definida
oecd_area
0 Ciencias Sociales, Enseñanza Comercial y Derecho
4 Humanidades y Artes
5 Ingeniería, Industria y Construcción
29 Servicios
35 Salud y Servicios Sociales
44 Ciencias
48 Agricultura
66 Educación
149294 Sin área definida
oecd_subarea
0 Enseñanza Comercial y Administración
2 Ciencias Sociales y del Comportamiento
4 Artes
5 Arquitectura y Construcción
29 Servicios de Seguridad
32 Ingeniería y Profesiones Afines
33 Servicios Personales
35 Medicina
36 Servicios de Transporte
44 Ciencias Físicas
48 Veterinaria
49 Ciencias de la Vida
50 Industria y Producción
54 Servicios Sociales
55 Periodismo e Información
65 Informática
66 Formación de Personal Docente
100 Humanidades
277 Derecho
388 Ciencias de la Educación
805 Protección del Medio Ambiente
815 Agricultura, Silvicultura y Pesca
873 Matemáticas y Estadísticas
149294 Sin área definida
area_carrera_generica
0 Publicidad
1 Administración de Empresas e Ing. Asociadas
2 Psicología
3 Ingeniería Comercial
4 Diseño
... ...
103881 Doctorado en Administración y Comercio
124390 Ingeniería en Industria de la Madera
149294 Sin área definida
181208 Ingeniería Civil en Agroindustrias
226551 Técnico en Teatro
[283 rows x 1 columns]
acreditada_carr
0 NO ACREDITADA
1 ACREDITADA
acreditada_inst
0 ACREDITADA
2 NO ACREDITADA
acre_inst_desde_hasta
0 20/12/2014 - 20/12/2017
2 NaN
4 20/05/2015 - 20/05/2020
6 08/12/2014 - 08/12/2017
32 23/12/2013 - 23/12/2017
... ...
2223 24/10/2012 - 24/10/2015
2367 23/04/2014 - 23/04/2017
3270 24/11/2012 - 24/11/2016
3347 29/12/2014 - 29/12/2019
4081 03/12/2014 - 03/12/2016
[79 rows x 1 columns]
acre_inst_anio
0 3.0
2 NaN
4 5.0
32 4.0
55 6.0
72 2.0
103 7.0
costo_proceso_titulacion
0 0
1 329850
2 262737
3 632078
4 154945
... ...
866768 320500
869333 368500
1034139 155000
1058859 536000
1171166 194250
[705 rows x 1 columns]
costo_obtencion_titulo_diploma
0 0
2 50000
6 110000
8 305000
32 49588
... ...
448648 140000
448854 185431
506489 162289
726464 134000
784971 158574
[186 rows x 1 columns]
costo_tit_explicacion_observacion
0 NaN
2 MATRICULA Y DEFENSA PROYECTO DE TITULO
3 MATRICULA, TRABAJO PROYECTO DE TITULO Y DEFENS...
6 LAS ACTIVIDADES DE TITULACION SON PARTE DEL PL...
8 DERECHO POR EXAMEN DE GRADO DE LICENCIATURA $2...
... ...
259811 CONCENTRACION NOTAS, DIPLOMA
398971 EN LA UNIVERSIDAD DE TARAPACÁ NO HAY OTROS COS...
518725 NO VIGENTE
611716 DERECHO DE TITULACION
736011 CERTIFICADO DE TITULO
[174 rows x 1 columns]
El siguiente bloque muestra el código utilizado para aplicar One Hot sobre las columnas de los años 2011, 2015 y 2019, tal como se detalla en la sección Correlación entre Columnas de Análisis Exploratorio.
df_sub = pd.concat([df1, df5, df9])
# Se obtienen los tipos de cada columa en un dataframe
df_sub_datatypes = (pd.DataFrame(df_sub.dtypes)
.reset_index()
.rename(columns = {0:'tipo', 'index' : 'columna'})
)
# para cada columna...
cols_name = list(df_sub)
init = cols_name.index("costo_proceso_titulacion") + 1
for i in range(init, len(df_sub_datatypes)):
# Si es que es de tipo object...
if str(df_sub_datatypes.iloc[i][1]) == 'object':
col_name = df_sub_datatypes.iloc[i][0]
# y no corresponde a una de las siguientes...
if (col_name in ["codigo_unico", "nomb_inst", "nomb_sede", "nomb_carrera", "acre_inst_desde_hasta"]
or col_name in ["costo_obtencion_titulo_diploma", "costo_tit_explicacion_observacion", "costo_proceso_titulacion"]) :
continue
cols_name.remove(col_name)
# se le aplica la transformación One Hot y se guarda.
df_one_hot = pd.get_dummies(df_sub[[col_name]], prefix=col_name)
df_one_hot.to_csv("one_hot/one_hot_" + col_name + ".csv", index = False)
El HeatMap de la sección Correlación entre columnas de Análisis Exploratorio se muestra a continuación
import seaborn
corr_sub = df_sub_one_hot.corr()
seaborn.set(rc={'figure.figsize':(16,16)})
seaborn.heatmap(corr_sub)
<AxesSubplot:>
A continuación se muestra el código para obtener los datos relacionados a la pregunta ¿Cómo se relaciona el área de conocimiento de la carrera con la edad y género de la persona que se matricula?.
# se analiza por año y luego se promedia
d = [df0, df1, df2, df3, df4, df5, df6, df7, df8, df9]
h1 = []
i = 2010
for df in d:
dfh = (df.query("area_conocimiento!='Sin área definida'")[["GEN_ALU","rango_edad", "area_conocimiento"]]
.groupby(by=["GEN_ALU","rango_edad", "area_conocimiento"])
.size()
.reset_index()
.rename(columns = {0:'total'})
)
dfh["anio"] = [i]*len(dfh)
i+=1
h1.append(dfh.copy())
#concatenación y mapeo
dfh1 = (pd.concat(h1)[["GEN_ALU","rango_edad", "area_conocimiento", "total"]]
.groupby(by=["GEN_ALU","rango_edad", "area_conocimiento"])
.mean()
.reset_index()
)
dfh1[["GEN_ALU"]] = dfh1[["GEN_ALU"]].replace({1:"Hombre", 2:"Mujer"})
dfh1 = (dfh1.replace({"SIN INFORMACION": "Sin información", "Ciencias Sociales": "C. Sociales"}))
El siguiente es el código utilizado para obtener los datos del gráfico que responde a la pregunta ¿Existe una correlación entre el costo de las carreras y su ubicación geográfica? ¿Varía esto a través de los años?
pd.set_option('display.float_format', lambda x: '%.2f' % x)
d = [df1, df3, df5, df7, df9]
h2 = []
i = 2011
for df in d:
try:
dfh = df.query("vigencia_carrera!='NO VIGENTE'")
except:
dfh = df
dfh = (dfh[["codigo_unico","valor_arancel", "region_sede"]]
.drop_duplicates()[["region_sede", "valor_arancel"]]
.groupby(["region_sede"])
.mean()
.reset_index()
.rename(columns = {"valor_arancel":'arancel_promedio_pesos'})
)
dfh["anio"] = [i]*len(dfh)
i+=1
h2.append(dfh.copy())
df_arancel_original = pd.concat(h2)
df_UF = pd.read_csv("UF.csv").rename(columns={"Periodo": "anio"})
df_UF["UF"] = df_UF["UF"].astype(float)
df_arancel_original = pd.merge(df_arancel_original, df_UF, how = "inner", on = ["anio"])
df_arancel_original["arancel_promedio_UF"] = df_arancel_original.arancel_promedio_pesos/df_arancel_original.UF
df_arancel_original = df_arancel_original[["anio", "region_sede", "arancel_promedio_UF"]].sort_values("anio", ascending = False)
df_arancel_mapeado = (df_arancel_original.replace({'Arica y Parinacota': 1, 'Tarapacá': 2, 'Antofagasta': 3, 'Atacama': 4, 'Coquimbo': 5, 'Valparaíso': 6, 'Metropolitana': 7, "Lib. Gral B. O'Higgins": 8, 'Maule': 9, 'Ñuble': 10, 'Biobío': 11, 'La Araucanía': 12, 'Los Ríos': 13, 'Los Lagos': 14, 'Aysén': 15, 'Magallanes': 16}))
df_arancel_mapeo_regiones = pd.DataFrame({"Region": ['Arica y Parinacota', 'Tarapacá', 'Antofagasta', 'Atacama', 'Coquimbo', 'Valparaíso', 'Metropolitana', "Lib. Gral B. O'Higgins", 'Maule', 'Ñuble', 'Biobío', 'La Araucanía', 'Los Ríos', 'Los Lagos', 'Aysén', 'Magallanes'], "Equivalente": list(range(1,17))})
# Se obtienen los tipos de cada columa en un dataframe
sub_df_0to7_datatypes = (pd.DataFrame(sub_df_0to7.dtypes)
.reset_index()
.rename(columns = {0:'tipo', 'index' : 'columna'})
)
# para cada columna...
cols_name = list(sub_df_0to7).remove('GEN_ALU')
df_sub_one_hot = pd.get_dummies(sub_df_0to7[['GEN_ALU']], prefix='GEN_ALU')
for i in range(1, len(sub_df_0to7_datatypes)):
col_name = sub_df_0to7_datatypes.iloc[i][0]
# Si es que es de tipo object...
if str(sub_df_0to7_datatypes.iloc[i][1]) == 'object':
# se le aplica la transformación One Hot
df_one_hot = pd.get_dummies(sub_df_0to7[[col_name]], prefix=col_name)
else:
df_one_hot = sub_df_0to7[[col_name]]
df_sub_one_hot = pd.merge(df_sub_one_hot, df_one_hot, left_index=True, right_index=True)
df_sub_one_hot = df_sub_one_hot.reset_index(drop=True)
import seaborn
# Se aplica One Hot
corr_sub = df_sub_one_hot.corr()
seaborn.set(rc={'figure.figsize':(16,16)})
seaborn.heatmap(corr_sub)
<AxesSubplot:>
Las funciones train(Classifier, data_dict) y get_data_dict(df, testSize) se muestran
a continuación
from sklearn.metrics import f1_score, recall_score, precision_score
from sklearn.model_selection import train_test_split
def get_data_dict(df, testSize):
data_train, data_test, ytrain, ytest = train_test_split(df, df['Class'], test_size=testSize, stratify=df['Class'])
diferencia = ytrain.value_counts()[False]-ytrain.value_counts()[True]
data_train = data_train.reset_index(drop=True)
# oversampling sobre la clase True
idx = np.random.choice(data_train[data_train['Class'] == True].index, size=diferencia)
data_oversampled = pd.concat([data_train, data_train.iloc[idx]])
print("Data oversampled on class 'True'")
print(data_oversampled['Class'].value_counts())
# subsampling sobre la clase False
idx = np.random.choice(data_train.loc[data_train.Class == False].index, size=diferencia, replace=False)
data_subsampled = data_train.drop(data_train.iloc[idx].index)
print("Data subsampled on class 'False'")
print(data_subsampled['Class'].value_counts())
# Se definen los conjuntos de testeo
X_test = data_test[data_train.columns[:-1]]
y_test = data_test[data_train.columns[-1]]
# datos entrenamiento "originales"
X_orig = data_train[data_train.columns[:-1]]
y_orig = data_train[data_train.columns[-1]]
# datos entrenamiento "oversampleados"
X_over = data_oversampled[data_train.columns[:-1]]
y_over = data_oversampled[data_train.columns[-1]]
# datos entrenamiento "subsampleados"
X_subs = data_subsampled[data_train.columns[:-1]]
y_subs = data_subsampled[data_train.columns[-1]]
return {'X_test': X_test, 'y_test': y_test, 'X_orig': X_orig, 'y_orig': y_orig, 'X_over': X_over, 'y_over': y_over, 'X_subs': X_subs, 'y_subs': y_subs}
from sklearn.metrics import classification_report
def train(Classifier, data_dict):
print("::::::::::Datos originales")
clf_orig = Classifier()
clf_orig.fit(data_dict['X_orig'], data_dict['y_orig'])
pred_orig = clf_orig.predict(data_dict['X_test'])
print(classification_report(data_dict['y_test'], pred_orig))
print("::::::::::Datos con oversampling")
clf_over = Classifier()
clf_over.fit(data_dict['X_over'], data_dict['y_over'])
pred_over = clf_over.predict(data_dict['X_test'])
print(classification_report(data_dict['y_test'], pred_over))
print("::::::::::Datos con subsampling")
clf_subs = Classifier()
clf_subs.fit(data_dict['X_subs'], data_dict['y_subs'])
pred_subs = clf_subs.predict(data_dict['X_test'])
print(classification_report(data_dict['y_test'], pred_subs))
return clf_orig, clf_over, clf_subs
Para entrenar cada modelo y ver sus métricas se hizo como sigue;
data_dict = get_data_dict(df_sub_one_hot, testSize = 0.995)
Data oversampled on class 'True' True 9205 False 9205 Name: Class, dtype: int64 Data subsampled on class 'False' True 955 False 955 Name: Class, dtype: int64
from sklearn.tree import DecisionTreeClassifier
print("Resultados para Árbol de Decisión")
DTC_orig, DTC_over, DTC_subs = train(DecisionTreeClassifier, data_dict)
Resultados para Árbol de Decisión
::::::::::Datos originales
precision recall f1-score support
False 0.97 0.98 0.97 1831973
True 0.76 0.68 0.72 190001
accuracy 0.95 2021974
macro avg 0.86 0.83 0.84 2021974
weighted avg 0.95 0.95 0.95 2021974
::::::::::Datos con oversampling
precision recall f1-score support
False 0.98 0.95 0.96 1831973
True 0.60 0.77 0.68 190001
accuracy 0.93 2021974
macro avg 0.79 0.86 0.82 2021974
weighted avg 0.94 0.93 0.93 2021974
::::::::::Datos con subsampling
precision recall f1-score support
False 0.99 0.90 0.94 1831973
True 0.47 0.88 0.61 190001
accuracy 0.89 2021974
macro avg 0.73 0.89 0.78 2021974
weighted avg 0.94 0.89 0.91 2021974
from sklearn.naive_bayes import GaussianNB # Naive bayes
print("Resultados para Naive bayes")
NB_orig, NB_over, NB_subs = train(GaussianNB, data_dict)
Resultados para Naive bayes
::::::::::Datos originales
precision recall f1-score support
False 0.99 0.80 0.89 1831973
True 0.33 0.93 0.48 190001
accuracy 0.81 2021974
macro avg 0.66 0.87 0.69 2021974
weighted avg 0.93 0.81 0.85 2021974
::::::::::Datos con oversampling
precision recall f1-score support
False 0.99 0.79 0.88 1831973
True 0.32 0.96 0.48 190001
accuracy 0.80 2021974
macro avg 0.66 0.87 0.68 2021974
weighted avg 0.93 0.80 0.84 2021974
::::::::::Datos con subsampling
precision recall f1-score support
False 1.00 0.79 0.88 1831973
True 0.32 0.96 0.48 190001
accuracy 0.81 2021974
macro avg 0.66 0.88 0.68 2021974
weighted avg 0.93 0.81 0.84 2021974
from sklearn.neighbors import KNeighborsClassifier
print("Resultados para K Neighbors")
KNN_orig, KNN_over, KNN_subs = train(KNeighborsClassifier, data_dict)
Resultados para K Neighbors
::::::::::Datos originales
precision recall f1-score support
False 0.96 0.98 0.97 1831973
True 0.74 0.59 0.65 190001
accuracy 0.94 2021974
macro avg 0.85 0.78 0.81 2021974
weighted avg 0.94 0.94 0.94 2021974
::::::::::Datos con oversampling
precision recall f1-score support
False 0.98 0.89 0.93 1831973
True 0.45 0.86 0.59 190001
accuracy 0.89 2021974
macro avg 0.72 0.87 0.76 2021974
weighted avg 0.93 0.89 0.90 2021974
::::::::::Datos con subsampling
precision recall f1-score support
False 0.99 0.80 0.88 1831973
True 0.32 0.92 0.47 190001
accuracy 0.81 2021974
macro avg 0.65 0.86 0.68 2021974
weighted avg 0.93 0.81 0.85 2021974
from sklearn.svm import SVC # Support Vector Machine classifier
print("Resultados para Support Vector Machine")
SVM_orig, SVM_over, SVM_subs = train(SVC, data_dict)
Resultados para Support Vector Machine ::::::::::Datos originales
precision recall f1-score support
False 0.91 1.00 0.95 1831973
True 0.00 0.00 0.00 190001
accuracy 0.91 2021974
macro avg 0.45 0.50 0.48 2021974
weighted avg 0.82 0.91 0.86 2021974
::::::::::Datos con oversampling
Para entrenar los clasificadores Árbol de Decisión y Naive bayes con el de los datos se utilizó el siguiente código:
data_dict = get_data_dict(df_sub_one_hot, testSize = 0.3)
Data oversampled on class 'True' True 1288824 False 1288824 Name: Class, dtype: int64 Data subsampled on class 'False' True 133669 False 133669 Name: Class, dtype: int64
print("Resultados para Árbol de Decisión")
DTC_orig, DTC_over, DTC_subs = train(DecisionTreeClassifier, data_dict)
Resultados para Árbol de Decisión
::::::::::Datos originales
precision recall f1-score support
False 0.97 0.99 0.98 552354
True 0.85 0.75 0.80 57287
accuracy 0.96 609641
macro avg 0.91 0.87 0.89 609641
weighted avg 0.96 0.96 0.96 609641
::::::::::Datos con oversampling
precision recall f1-score support
False 0.99 0.92 0.96 552354
True 0.55 0.95 0.70 57287
accuracy 0.92 609641
macro avg 0.77 0.94 0.83 609641
weighted avg 0.95 0.92 0.93 609641
::::::::::Datos con subsampling
precision recall f1-score support
False 0.99 0.92 0.96 552354
True 0.55 0.95 0.70 57287
accuracy 0.92 609641
macro avg 0.77 0.93 0.83 609641
weighted avg 0.95 0.92 0.93 609641
print("Resultados para Naive bayes")
NB_orig, NB_over, NB_subs = train(GaussianNB, data_dict)
Resultados para Naive bayes
::::::::::Datos originales
precision recall f1-score support
False 0.99 0.80 0.89 552354
True 0.33 0.95 0.49 57287
accuracy 0.81 609641
macro avg 0.66 0.87 0.69 609641
weighted avg 0.93 0.81 0.85 609641
::::::::::Datos con oversampling
precision recall f1-score support
False 0.99 0.79 0.88 552354
True 0.32 0.96 0.48 57287
accuracy 0.80 609641
macro avg 0.66 0.87 0.68 609641
weighted avg 0.93 0.80 0.84 609641
::::::::::Datos con subsampling
precision recall f1-score support
False 0.99 0.79 0.88 552354
True 0.32 0.96 0.48 57287
accuracy 0.80 609641
macro avg 0.66 0.87 0.68 609641
weighted avg 0.93 0.80 0.84 609641
El código a continuación está en lenguaje R.
library(magrittr)
library(dplyr)
library(tidyr)
library('arules')
library('arulesViz')
library('sjPlot')
#Selección de atributos, año 2019
datos_2019<-read.csv(file = "datos_limpios/2019.csv", sep = ",")[ ,c("jornada","rango_edad","dur_total_carr","tipo_inst_3","area_conocimiento","region_sede","acreditada_inst","valor_arancel","valor_matricula")]
#Se filtran valores faltantes
datos_2019<-datos_2019[complete.cases(datos_2019),]
#Creación de categorías por percentiles para el valor de arancel
Percentile_00_A2019 = min(datos_2019$valor_arancel)
Percentile_33_A2019 = quantile(datos_2019$valor_arancel, 0.33333)
Percentile_67_A2019 = quantile(datos_2019$valor_arancel, 0.66667)
Percentile_100_A2019 = max(datos_2019$valor_arancel)
RB = rbind(Percentile_00_A2019, Percentile_33_A2019, Percentile_67_A2019, Percentile_100_A2019)
dimnames(RB)[[2]] = "Value"
#Creación de categorías por percentiles para el valor de matrícula
Percentile_00_M2019 = min(datos_2019$valor_matricula)
Percentile_33_M2019 = quantile(datos_2019$valor_matricula, 0.33333)
Percentile_67_M2019 = quantile(datos_2019$valor_matricula, 0.66667)
Percentile_100_M2019 = max(datos_2019$valor_matricula)
RBM = rbind(Percentile_00_M2019, Percentile_33_M2019, Percentile_67_M2019, Percentile_100_M2019)
dimnames(RBM)[[2]] = "Value"
datos_2019$Categoria_arancel[datos_2019$valor_arancel >= Percentile_00_A2019 & datos_2019$valor_arancel < Percentile_33_A2019] = "AB"
datos_2019$Categoria_arancel[datos_2019$valor_arancel >= Percentile_33_A2019 & datos_2019$valor_arancel < Percentile_67_A2019] = "AM"
datos_2019$Categoria_arancel[datos_2019$valor_arancel >= Percentile_67_A2019 & datos_2019$valor_arancel <= Percentile_100_A2019] = "AA"
datos_2019$valor_arancel <- NULL
datos_2019$Categoria_matricula[datos_2019$valor_matricula >= Percentile_00_M2019 & datos_2019$valor_matricula < Percentile_33_M2019] = "MB"
datos_2019$Categoria_matricula[datos_2019$valor_matricula >= Percentile_33_M2019& datos_2019$valor_matricula < Percentile_67_M2019] = "MM"
datos_2019$Categoria_matricula[datos_2019$valor_matricula >= Percentile_67_M2019 & datos_2019$valor_matricula <= Percentile_100_M2019] = "MA"
datos_2019$valor_matricula <- NULL
| jornada | rango_edad | dur_total_carr | tipo_inst_3 | area_conocimiento | region_sede | acreditada_inst | Categoria_arancel | Categoria_matricula |
|---|---|---|---|---|---|---|---|---|
| Diurno | 15 a 19 años | 10 | Universidades Privadas | Salud | Coquimbo | ACREDITADA | AM | MA |
| Diurno | 20 a 24 años | 10 | Universidades Estatales CRUCH | Ciencias Sociales | Metropolitana | ACREDITADA | AA | MM |
| Diurno | 25 a 29 años | 10 | Universidades Privadas CRUCH | Humanidades | Metropolitana | ACREDITADA | AA | MB |
| Vespertino | 15 a 19 años | 5 | Institutos Profesionales | Administración y Comercio | Metropolitana | NO ACREDITADA | AB | MB |
| Vespertino | 20 a 24 años | 5 | Institutos Profesionales | Administración y Comercio | Metropolitana | ACREDITADA | AB | MM |
| Diurno | 20 a 24 años | 10 | Universidades Estatales CRUCH | Tecnología | Metropolitana | ACREDITADA | AA | MM |
#CSV con atributos seleccionados
write.csv(datos_2019,"datos_limpios/2019_P4.csv", row.names = FALSE)
## Eclat
##
## parameter specification:
## tidLists support minlen maxlen target ext
## FALSE 0.04 1 10 frequent itemsets TRUE
##
## algorithmic control:
## sparse sort verbose
## 7 -2 TRUE
##
## Absolute minimum support count: 50740
##
## create itemset ...
## set transactions ...[78 item(s), 1268505 transaction(s)] done [0.50s].
## sorting and recoding items ... [39 item(s)] done [0.06s].
## creating bit matrix ... [39 row(s), 1268505 column(s)] done [0.15s].
## writing ... [1230 set(s)] done [0.08s].
## Creating S4 object ... done [0.00s].
| items | support | count |
|---|---|---|
| {ACREDITADA} | 0.93 | 1174652 |
| {Diurno} | 0.70 | 892899 |
| {ACREDITADA,Diurno} | 0.68 | 860341 |
| {Metropolitana} | 0.48 | 613381 |
| {20 a 24 años} | 0.47 | 598695 |
| {20 a 24 años,ACREDITADA} | 0.46 | 578644 |
itemFrequencyPlot(df2019, topN=10, type="absolute", main="Items más frecuentes")
## Apriori
##
## Parameter specification:
## confidence minval smax arem aval originalSupport maxtime support minlen maxlen target ext
## 0.3 0.1 1 none FALSE TRUE 5 0.04 2 10 rules TRUE
##
## Algorithmic control:
## filter tree heap memopt load sort verbose
## 0.1 TRUE TRUE FALSE TRUE 2 TRUE
##
## Absolute minimum support count: 50740
##
## set item appearances ...[0 item(s)] done [0.00s].
## set transactions ...[78 item(s), 1268505 transaction(s)] done [0.50s].
## sorting and recoding items ... [39 item(s)] done [0.08s].
## creating transaction tree ... done [0.84s].
## checking subsets of size 1 2 3 4 5 6 7 done [0.02s].
## writing ... [3484 rule(s)] done [0.00s].
## creating S4 object ... done [0.25s].
tab_df(rules2019.sorted.first10_dataframe)
| rules | support | confidence | coverage | lift | count |
|---|---|---|---|---|---|
| {5,AB,ACREDITADA,MB} => {Centros de Formación Técnica} | 0.04 | 0.59 | 0.07 | 5.46 | 55721 |
| {5,ACREDITADA,MB} => {Centros de Formación Técnica} | 0.04 | 0.58 | 0.08 | 5.41 | 56346 |
| {ACREDITADA,AM,Diurno,Institutos Profesionales,MA} => {8} | 0.05 | 0.99 | 0.05 | 4.94 | 64072 |
| {AM,Diurno,Institutos Profesionales,MA} => {8} | 0.05 | 0.98 | 0.05 | 4.93 | 64149 |
| {Institutos Profesionales,MA,Tecnología} => {8} | 0.04 | 0.97 | 0.05 | 4.88 | 56161 |
| {ACREDITADA,Institutos Profesionales,MA,Tecnología} => {8} | 0.04 | 0.97 | 0.05 | 4.88 | 56084 |
| {AM,Institutos Profesionales,MA,Tecnología} => {8} | 0.04 | 0.97 | 0.04 | 4.88 | 53010 |
| {ACREDITADA,AM,Institutos Profesionales,MA,Tecnología} => {8} | 0.04 | 0.97 | 0.04 | 4.87 | 52933 |
| {ACREDITADA,Diurno,Institutos Profesionales,MA} => {8} | 0.05 | 0.97 | 0.06 | 4.87 | 68659 |
| {20 a 24 años,ACREDITADA,AM,Institutos Profesionales,MA} => {8} | 0.04 | 0.97 | 0.04 | 4.86 | 52106 |
#Reglas que implican Arancel Alto (AA)
rhs_AA_rules2019 <- sort(subset(rules2019, subset = rhs %in% "AA"), by = "lift")
#inspect(head(rhs_AA_rules2019))
rhs_AA_rules2019_dataframe <- as(rhs_AA_rules2019, 'data.frame')
tab_df(head(rhs_AA_rules2019_dataframe))
| rules | support | confidence | coverage | lift | count |
|---|---|---|---|---|---|
| {ACREDITADA,Diurno,MA,Salud,Universidades Privadas} => {AA} | 0.04 | 0.92 | 0.05 | 2.76 | 56737 |
| {Diurno,MA,Salud,Universidades Privadas} => {AA} | 0.05 | 0.92 | 0.05 | 2.75 | 58413 |
| {10,ACREDITADA,Diurno,MA,Metropolitana} => {AA} | 0.05 | 0.91 | 0.06 | 2.73 | 66365 |
| {ACREDITADA,MA,Salud,Universidades Privadas} => {AA} | 0.05 | 0.91 | 0.05 | 2.73 | 57557 |
| {10,ACREDITADA,MA,Metropolitana} => {AA} | 0.05 | 0.91 | 0.06 | 2.72 | 69277 |
| {10,ACREDITADA,Diurno,MA,Metropolitana,Universidades Privadas} => {AA} | 0.04 | 0.90 | 0.05 | 2.70 | 55948 |
rhs_AA_subrules2019 <- head(rhs_AA_rules2019, n = 50, by = "lift")
plot(rhs_AA_subrules2019, method = "graph")
rhs_AM_rules2019 <- sort(subset(rules2019, subset = rhs %in% "AM"), by = "lift")
rhs_AM_rules2019_dataframe <- as(rhs_AM_rules2019, 'data.frame')
tab_df(head(rhs_AM_rules2019_dataframe))
| rules | support | confidence | coverage | lift | count |
|---|---|---|---|---|---|
| {8,ACREDITADA,Institutos Profesionales,MA,Metropolitana} => {AM} | 0.04 | 0.98 | 0.04 | 2.93 | 55267 |
| {8,Institutos Profesionales,MA,Metropolitana} => {AM} | 0.04 | 0.98 | 0.04 | 2.93 | 55267 |
| {ACREDITADA,Institutos Profesionales,MA,Metropolitana} => {AM} | 0.05 | 0.97 | 0.05 | 2.90 | 58270 |
| {Institutos Profesionales,MA,Metropolitana} => {AM} | 0.05 | 0.96 | 0.05 | 2.88 | 58398 |
| {Institutos Profesionales,MA,Tecnología} => {AM} | 0.04 | 0.95 | 0.05 | 2.83 | 54489 |
| {ACREDITADA,Institutos Profesionales,MA,Tecnología} => {AM} | 0.04 | 0.95 | 0.05 | 2.83 | 54412 |
rhs_AM_subrules2019 <- head(rhs_AM_rules2019, n = 50, by = "lift")
plot(rhs_AM_subrules2019, method = "graph")
rhs_AB_rules2019 <- sort(subset(rules2019, subset = rhs %in% "AB"), by = "lift")
rhs_AB_rules2019_dataframe <- as(rhs_AB_rules2019, 'data.frame')
tab_df(head(rhs_AB_rules2019_dataframe))
| rules | support | confidence | coverage | lift | count |
|---|---|---|---|---|---|
| {5,Institutos Profesionales,MB} => {AB} | 0.04 | 1.00 | 0.04 | 3.00 | 54192 |
| {5,Centros de Formación Técnica,MB} => {AB} | 0.05 | 0.99 | 0.05 | 2.97 | 63287 |
| {5,ACREDITADA,Centros de Formación Técnica,MB} => {AB} | 0.04 | 0.99 | 0.04 | 2.97 | 55721 |
| {5,Diurno,MB} => {AB} | 0.05 | 0.99 | 0.05 | 2.97 | 62959 |
| {5,ACREDITADA,Diurno,MB} => {AB} | 0.04 | 0.99 | 0.04 | 2.96 | 54118 |
| {5,MB} => {AB} | 0.10 | 0.98 | 0.11 | 2.96 | 131416 |
rhs_AB_subrules2019 <- head(rhs_AB_rules2019, n = 50, by = "lift")
plot(rhs_AB_subrules2019, method = "graph")